Unity Shader GUI

Created by miccall (转载请注明出处 miccall.tech)

GUI先继承 ShaderGUI 类 , 然后 重写 OnGUI 方法

        public class MyLightingShaderGUI : ShaderGUI
        {
                publicoverridevoid OnGUI (MaterialEditor editor , MaterialProperty [] properties ) 
                {

                }
        }

OnGUI有两个参数 ,第一个是 editor , 指代我们当前的编辑器 。
第二个是 properties 数组 ,里面包含了我们在当前材质的shader中,定义的一些公开属性

我们为了以后方便计算 ,把这些设置为全局变量

    private Material _target;
    private MaterialEditor _editor;
    private MaterialProperty[] _properties;

并且在 OnGUI 中为他们赋值

        //当前编辑对象的material
        _target = editor.target as Material;
        _editor = editor ;
        _properties = properties ;

然后我们根据shader中的属性,挨个为他们进行属性GUI绘制

首先,在shader中第一个 :

        _Tint ("Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Albedo", 2D) = "white" {}

我们先来获取他的属性 :

        var mainTex  =  FindProperty("_MainTex") ;  

这个函数是我们自己定义的,原来的定义也差不多:

        private   MaterialProperty  FindProperty(  string  name  ) {
          return   FindProperty  (  name  ,  _properties  ) ;
        }

同理,Tint 也一样

接下来我们自定义个函数

        privatestaticreadonly  GUIContent  StaticLabel  =  new  GUIContent();
        privatestatic   GUIContent  MakeLabel  (   MaterialProperty   property  ,string   tooltip  =  null  )
        {
                StaticLabel.text  =  property.displayName;
                StaticLabel.tooltip  =  tooltip; 
                return  StaticLabel ;
        }

        privatestatic    GUIContent   MakeLabel  (   string  text , string tooltip  = null )
        {
                StaticLabel.text = text;
                StaticLabel.tooltip = tooltip;
                return    StaticLabel;
        }

当然,这是一个重载函数 ,目的是写一个 label 来展示标识 ,这个label的内容,可以直接使用属性本身的显示名字(也就是shader里面定义的显示名字) ,也可以通过重载,来我们自己重写一个名字。

tooltip 是一个提示目的的标语,默认可以为空 。

然后介绍一个方法 :TexturePropertySingleLine 用于显示具有附加内联特性的纹理属性控件的方法。

        public Rect TexturePropertySingleLine(GUIContent label, MaterialProperty textureProp);
        public Rect TexturePropertySingleLine(GUIContent label, MaterialProperty textureProp, MaterialProperty extraProperty1);
        public Rect TexturePropertySingleLine(GUIContent label, MaterialProperty textureProp, MaterialProperty extraProperty1, MaterialProperty extraProperty2);

第一个参数是label ,就是显示名字 ,第二个就是属性 ,第三四个就是附加属性了 ,

我们把texture 和 Tint 结合到一起 :

        _editor.TexturePropertySingleLine(MakeLabel(mainTex,"Albedo(RGB)"),mainTex,FindProperty("_Tint"));

这样的话,我们的shader面板就变成:

如果我们想在他的上面加一个标语:

        GUILayout.Label("MainMaps",EditorStyles.boldLabel);

接下来,我们继续添加 metallic 贴图 的GUI :

    [NoScaleOffset]_MetallicMap("Metallic",2D)="white"{}
    [Gamma]_Metallic("Metallic",Range(0,1))=0

            var  map  =  FindProperty("_MetallicMap");

                EditorGUI.BeginChangeCheck();

                _editor.TexturePropertySingleLine(
                        MakeLabel(map,"Metallic(R)"),map,
                        map.textureValue ? null : FindProperty("_Metallic") 
                        );

                if(EditorGUI.EndChangeCheck()){
                        SetKeyword("_METALLIC_MAP",map.textureValue); 
                }

我们可以使用

         EditorGUI.BeginChangeCheck 
    和  
        EditorGUI.EndChangeCheck 

        方法检查某些内容是否已更改。

第一种方法定义了我们想要开始跟踪更改的点。
第二种方法标记结束,并返回是否进行了更改。

        private void SetKeyword(string keyword,bool state){
                if(state){
                        //将关键字添加到着色器
                        _target.EnableKeyword(keyword);
                }
                else{
                        _target.DisableKeyword(keyword);
                }
        }

SetKeyword 的目的是为了多分支编译shader版本 ,我们用

    #pragmas   hader_feature   _METALLIC_MAP 

来控制 金属度贴图的使用

        #if   defined  (_METALLIC_MAP)
                return tex2D( _MetallicMap , i.uv.xy).r;
        #else
                return _Metallic;
        #endif

然后是Smoothness:

    _Smoothness("Smoothness",Range(0,1))=0.1

smooness 有三种,
第一个就是固定silder ,
第二种是在 metallic 的alpha 通道
第三种是在 albedo的alpha 通道

我们就要有一个选择器:

    #pragma shader_feature _ _SMOOTHNESS_ALBEDO  _SMOOTHNESS_METALLIC

        float GetSmoothness ( Interpolators i ) {
                float  smoothness = 1 ;
                #if defined( _SMOOTHNESS_ALBEDO )
                        smoothness = tex2D(_MainTex,i.uv.xy).a;
                #elif  defined(_SMOOTHNESS_METALLIC)&&defined(_METALLIC_MAP)
                   smoothness = tex2D(_MetallicMap,i.uv.xy).a;
                #endif
                return  smoothness * _Smoothness ; 
        }

在GUI中,我们开控制他的选择 :

    private  enum   SmoothnessSource {  Uniform , Albedo , Metallic  }

        private void DoSmoothness () {
                // default ? 
                var source = SmoothnessSource.Uniform ;
                if (IsKeywordEnabled("_SMOOTHNESS_ALBEDO")) {
                        source = SmoothnessSource.Albedo ;
                }
                else if ( IsKeywordEnabled("_SMOOTHNESS_METALLIC")) {
                        source = SmoothnessSource.Metallic;
                }

                var slider = FindProperty("_Smoothness");
                EditorGUI.indentLevel += 2;
                _editor.ShaderProperty(slider, MakeLabel(slider));
                EditorGUI.indentLevel += 1;
                EditorGUI.BeginChangeCheck();
                source = ( SmoothnessSource ) EditorGUILayout.EnumPopup( MakeLabel("Source"), source );

                if (    EditorGUI.EndChangeCheck()    ) {
                        RecordAction("Smoothness Source");
                        SetKeyword("_SMOOTHNESS_ALBEDO", source == SmoothnessSource.Albedo);
                        SetKeyword("_SMOOTHNESS_METALLIC", source == SmoothnessSource.Metallic);
                }
                EditorGUI.indentLevel -= 3;
        }

    IsKeywordEnabled 是判断当前的 key word 是否是启用状态 :

        private  bool   IsKeywordEnabled ( string keyword  ) {
                return   _target.IsKeywordEnabled( keyword ) ;
        }

用户在面板上选取的值,我们通过这个获取

    source=(SmoothnessSource)EditorGUILayout.EnumPopup(MakeLabel("Source"),source); 

下面就是判断这个值,然后自定义开关一个 keywords 了

再接下来,就是normal map

    [NoScaleOffset]_NormalMap("Normals",2D)="bump"{}
    _BumpScale("BumpScale",Float)=1

        privatevoid   DoNormals ()   {
                var  map  = FindProperty("_NormalMap");
                _editor.TexturePropertySingleLine(
                        MakeLabel(map),map,
                        map.textureValue?FindProperty("_BumpScale"):null
                );
        }

自发光贴图:

        private  void  DoEmission(){
                var map=FindProperty("_EmissionMap");
                EditorGUI.BeginChangeCheck();
                _editor.TexturePropertyWithHDRColor(
                        MakeLabel("Emission(RGB)"),map,FindProperty("_Emission"),
                        EmissionConfig,false
                );
                if(EditorGUI.EndChangeCheck()){
                        SetKeyword("_EMISSION_MAP",map.textureValue);
                }
        }

        float3GetEmission(Interpolatorsi){
                #ifdefined(FORWARD_BASE_PASS)
                        #ifdefined(_EMISSION_MAP)
                                returntex2D(_EmissionMap,i.uv.xy)*_Emission;
                        #else
                                return_Emission;
                        #endif
                #else
                        return0;
                #endif
        }